package utils

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"time"

	"github.com/pkg/sftp"
	"golang.org/x/crypto/ssh"
)

// 获取一个STFP客户端连接
func Connect(user string, keyPath string, host string, port string) *sftp.Client {

	auth := []ssh.AuthMethod{publicKeyAuthFunc(keyPath)}

	config := &ssh.ClientConfig{
		User:            user,
		Auth:            auth,
		Timeout:         30 * time.Second,
		HostKeyCallback: hostKeyCallback,
	}

	// 连接SSH服务端
	addr := fmt.Sprintf("%s:%s", host, port)
	client, err := ssh.Dial("tcp", addr, config)
	if err != nil {
		fmt.Println("连接SSH服务端失败")
		panic(err)
	}

	// 创建SFTP客户端
	sftpClient, err := sftp.NewClient(client)
	if err != nil {
		fmt.Println("创建SFTP客户端失败")
		panic(err)
	}
	return sftpClient
}

// 上传文件
func UploadFile(sftpClient *sftp.Client, localFilename string, remotePath string) {

	// 打开本地文件
	file, err := os.Open(localFilename)
	if err != nil {
		fmt.Printf("打开本地文件失败：%s\n", localFilename)
		panic(err)
	}
	defer file.Close()

	// 创建远程文件夹
	remoteFileName := filepath.Join(remotePath, filepath.Base(localFilename))
	tempRemoteFileName := remoteFileName + ".tmp"
	err = sftpClient.MkdirAll(remotePath)
	if err != nil {
		fmt.Printf("创建远程文件夹失败：%s\n", remotePath)
		panic(err)
	}

	// 创建远程文件，先写入临时文件
	dstFile, err := sftpClient.Create(tempRemoteFileName)
	if err != nil {
		fmt.Printf("创建远程文件失败：%s\n", tempRemoteFileName)
		panic(err)
	}
	defer dstFile.Close()

	// 读取本地文件
	bf, err := ioutil.ReadAll(file)
	if err != nil {
		fmt.Printf("读取远程文件失败：%s\n", localFilename)
		panic(err)
	}

	// 写入到远程文件
	_, writeFileErr := dstFile.Write(bf)
	if writeFileErr != nil {
		fmt.Printf("写入远程文件失败：%s\n", tempRemoteFileName)
		panic(writeFileErr)
	}

	// 修改为目标文件名
	renameErr := sftpClient.Rename(tempRemoteFileName, remoteFileName)
	if renameErr != nil {
		fmt.Printf("修改远程文件名%s为%s失败\n", tempRemoteFileName, remoteFileName)
		panic(renameErr)
	}
}

// 获取签名
func publicKeyAuthFunc(keyPath string) ssh.AuthMethod {
	// 读取密钥文件
	key, err := ioutil.ReadFile(keyPath)
	if err != nil {
		fmt.Printf("密钥文件读取失败%s\n", keyPath)
		panic(err)
	}
	// 签名
	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
		fmt.Printf("关键签名失败%s\n", keyPath)
		panic(err)
	}
	return ssh.PublicKeys(signer)
}

func hostKeyCallback(hostname string, remote net.Addr, key ssh.PublicKey) error {
	return nil
}
